/***************************************************************************
 *   Copyright (C) 2008 by Philipp Müller                                  *
 *   philipp.mueller@gmx.de                                                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

#include "iostream.h"
#include "vompglobal.h"


IOStream::IOStream( const QString & filePath, quint32 channel, VDR * vdr, StreamType streamType, QObject *parent ) : QIODevice( parent ),
        m_vdr( vdr ),
        m_fileLength( 0 ),
        m_streamPos( 0 ),
        m_sequential( false ),
        m_readyReadRequested( false ),
        m_streamStarted( false ),
        m_filePath( filePath ),
        m_channel( channel ),
        m_streamType( streamType ),
        m_readyReadSize( 0 )
{
    switch ( m_streamType )
    {

        case STREAM_MEDIA:
            m_fileLength = m_vdr->openMediaFile( filePath, 0, 0 );
            break;

        case STREAM_RECORDING:
            m_fileLength = m_vdr->openRecording( filePath );
            break;

        case STREAM_TV:
            m_sequential = true;
            m_fileLength = m_vdr->streamChannel( channel );
            if ( m_fileLength == 1 ) //Successful started stream
            {
                m_streamStarted = true;
                connect( m_vdr, SIGNAL( streamReadyRead() ), this, SLOT( streamDataReadyRead() ) );
            }
            else if ( m_fileLength == 0 ) //Stream not started
            {
//                 m_streamStarted = false;
            }
            // m_fileLength = 2 would be "connection lost"
            break;

        default:
            qWarning() << "IOStream::IOStream Error! StreamType unknown: " << streamType;
            break;
    }

    open( QIODevice::ReadOnly );

    qDebug() << "IOStream::IOStream was called with filePath: " << filePath << "  channel: " << channel << "  streamType: " << streamType;
}


IOStream::~IOStream()
{
    qDebug() << "IOStream::IOStream ~ called";

    if ( m_streamType == STREAM_TV )
    {
        m_vdr->stopStreaming();
    }
}


qint64 IOStream::readData( char * data, qint64 maxSize )
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::readData was called with maxSize: " << maxSize << "  Pos: " << m_streamPos;
#endif

    qint64 writen;

    switch ( m_streamType )
    {

        case STREAM_MEDIA:
            writen = m_vdr->readMedia( data, maxSize, m_streamPos );
            m_streamPos += writen;
            break;

        case STREAM_RECORDING:
            writen = m_vdr->readRecording( data, maxSize, m_streamPos );
            m_streamPos += writen;
            break;

        case STREAM_TV:
            while ( m_vdr->streamBytesAvailable() < maxSize )
            {
#ifdef NETWORK_DEBUG
                qDebug() << "IOStream::readData waiting for bytesAvailable";
#endif
                if( m_vdr->isStreaming() )
                {
                    waitForReadyRead( 2000 );
                }
                else
                {
                    maxSize = m_vdr->streamBytesAvailable(); //Will be 0 for channel getting unavailable
                }
            }

            writen = m_vdr->readDataFromBuffer( data, maxSize );

            m_readyReadSize = m_readyReadSize - writen;
            break;

        default:
            qWarning() << "IOStream::readData Error! StreamType unknown: " << m_streamType;
            writen = 0;
            break;
    }

#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::readData: We have send the data now bytesWritten: " << writen;
#endif

    return writen;
}


qint64 IOStream::writeData( const char * /* data */ , qint64 /* maxSize */ )
{
    qWarning() << "IOStream::writeData was called. Strange as unsupported call.";
    return 0;
}


bool IOStream::seek( qint64 pos )
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::seek() was called with new pos: " << pos << "  and fileLength: " << m_fileLength;
#endif

    if ( m_streamType == STREAM_TV )
    {
#ifdef NETWORK_DEBUG
        qWarning() << "IOStream::seek() was called for live-tv which is unseekable";
#endif
        return false;
    }

    QIODevice::seek( pos );

    pos = qMin<quint64> (( quint64 )pos, m_fileLength ); //Limit the seek

    m_streamPos = pos;

    if ( pos > m_fileLength )
    {
        qWarning() << "IOStream::seek() was called with new pos > fileLength";
        return false;
    }

    return true;
}


bool IOStream::isSequential() const
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::isSequential() was called. We returned" << m_sequential;
#endif

    return m_sequential;
}


bool IOStream::waitForReadyRead( int msecs )
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::waitForReadyRead was called";
#endif
    return m_vdr->waitForStreamReadyRead( msecs );
}


qint64 IOStream::pos() const
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::pos() was called. We returned pos:" << m_streamPos;
#endif

    return m_streamPos;
}


qint64 IOStream::size() const
{

    if ( m_streamType == STREAM_TV )
    {
#ifdef NETWORK_DEBUG
        qDebug() << "IOStream::size() was called. We returned size of buffer:" << bytesAvailable();
#endif
        return bytesAvailable();
    }
    else
    {
#ifdef NETWORK_DEBUG
        qDebug() << "IOStream::size() was called. We returned size:" << m_fileLength;
#endif
        return m_fileLength;
    }
}


qint64 IOStream::bytesAvailable() const
{
    if ( m_streamType == STREAM_TV )
    {
        if ( m_vdr->streamBytesAvailable() == 0 )
        {
#ifdef NETWORK_DEBUG
            qDebug() << "IOStream::bytesAvailable() was called with bytesAvailable = 0";
#endif
            m_vdr->waitForStreamReadyRead( 2000 );
        }

#ifdef NETWORK_DEBUG
        qDebug() << "IOStream::bytesAvailable() was called. bufferSize: " << m_vdr->streamBytesAvailable();
#endif

        return m_vdr->streamBytesAvailable() + QIODevice::bytesAvailable();
    }

    return QIODevice::bytesAvailable();
}


void IOStream::streamDataReadyRead()
{
#ifdef NETWORK_DEBUG
    qDebug() << "IOStream::streamDataReadyRead called";
#endif

    if ( !m_readyReadRequested )
    {
        m_readyReadRequested = true;
        qint64 size = bytesAvailable();

        if ( size > m_readyReadSize )
        {
            m_readyReadSize = size;
            emit readyRead();
        }

        m_readyReadRequested = false;

#ifdef NETWORK_DEBUG
        qDebug() << "IOStream::streamDataReadyRead readyReadEmitted";
#endif
    }
}
